package linkerddriver

import (
	"io"
	"os/exec"
)

type SimpleLinkerdDriver struct {
	config *LinkerdConfig
}

func NewSimpleLinkerdDriver(config *LinkerdConfig) (*SimpleLinkerdDriver, error) {
	if config.KubectlPath == `` {
		config.KubectlPath = `kubectl`
	}

	if config.LinkerdPath == `` {
		config.LinkerdPath = `linkerd`
	}

	if _, err := exec.LookPath(config.KubectlPath); err != nil {
		return nil, err
	}

	if _, err := exec.LookPath(config.LinkerdPath); err != nil {
		return nil, err
	}

	return &SimpleLinkerdDriver{config: config}, nil
}

func (ld *SimpleLinkerdDriver) Inject(namespace string) error {
	cmdInject := exec.Command(ld.config.LinkerdPath, `inject`, `-`)
	return ld.injectOrUninjectPipe(namespace, cmdInject)
}

func (ld *SimpleLinkerdDriver) Uninject(namespace string) error {
	cmdUnInject := exec.Command(ld.config.LinkerdPath, `uninject`, `-`)
	return ld.injectOrUninjectPipe(namespace, cmdUnInject)
}

func (ld *SimpleLinkerdDriver) injectOrUninjectPipe(namespace string, linkerdCmd *exec.Cmd) error {
	cmdGetYamls := exec.Command(ld.config.KubectlPath, `get`, `-n`, namespace, `deploy`, `-o`, `yaml`)
	cmdReDeploy := exec.Command(ld.config.KubectlPath, `apply`, `-f`, `-`)

	pipe(cmdGetYamls, linkerdCmd, cmdReDeploy)
	if err := cmdGetYamls.Run(); err != nil {
		return err
	}
	if err := linkerdCmd.Run(); err != nil {
		return err
	}
	if err := cmdReDeploy.Run(); err != nil {
		return err
	}

	return nil
}

func pipe(cmds ...*exec.Cmd) {
	for i, cmd := range cmds {
		if i > 0 {
			out, _ := cmds[i-1].StdoutPipe()
			in, _ := cmd.StdinPipe()
			go func() {
				defer func() {
					out.Close()
					in.Close()
				}()
				io.Copy(in, out)
			}()
		}
	}
}
